package com.pfs.internal.timestamp.repositories;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.hibernate.criterion.Criterion;

public abstract class BaseRepository<T, ID extends Serializable> implements CustomRepository<T, ID> {
	private final Class<T> persistentClass;
	@PersistenceContext
	EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public BaseRepository() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public BaseRepository(final Class<T> persistentClass) {
		super();
		this.persistentClass = persistentClass;
	}

	public List<T> findAll() {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<T> cq = cb.createQuery(getEntityClass());
		Root<T> rootEntry = cq.from(getEntityClass());
		CriteriaQuery<T> all = cq.select(rootEntry);
		TypedQuery<T> allQuery = entityManager.createQuery(all);
		return allQuery.getResultList();
	}

	public long count() {
		return countByCriteria();
	}
	
	public T findOne(ID id) {
		return entityManager.find(getEntityClass(), id);
	}

	public long countByCriteria(Criterion... criterion) {
		CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
		cq.select(cb.count(cq.from(getEntityClass())));

		return getEntityManager().createQuery(cq).getSingleResult();
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	public Class<T> getEntityClass() {
		return persistentClass;
	}

}
